#include "steganographyOnImage.h"
#include "BitOperation.h"
#include "LSBSteg.h"
#include "EMDSteg.h"
#include <bitset>
#include <random>
#include <QDebug>

SteganographyOnImage::SteganographyOnImage(QString &&fileName):m_carrierIamge(std::move(fileName)){}

SteganographyOnImage::SteganographyOnImage(const QString &fileName):m_carrierIamge(fileName){}

SteganographyOnImage::SteganographyOnImage(const QImage &image):m_carrierIamge(image){}

SteganographyOnImage::SteganographyOnImage(QImage &&image):m_carrierIamge(std::move(image)){}

bool SteganographyOnImage::setImage(const QString &fileName){
    this->m_carrierIamge=QImage(fileName);
    return !m_carrierIamge.isNull();
}

bool SteganographyOnImage::setImage(QString &&fileName)
{
    this->m_carrierIamge=QImage(fileName);
    return !m_carrierIamge.isNull();
}

bool SteganographyOnImage::setImage(const QImage &ima)
{
    this->m_carrierIamge=ima;
    return !m_carrierIamge.isNull();
}

bool SteganographyOnImage::setImage(QImage &&ima)
{
    this->m_carrierIamge=std::move(ima);
    return !m_carrierIamge.isNull();
}

bool SteganographyOnImage::imbedded(const QByteArray &msg, Method method)
{
    auto data_car=m_carrierIamge.bits();
    switch (method) {
    case LSB:
        clr_bit(data_car[0],0);
        return LSBSteg::lsbImbedded(data_car+1,m_carrierIamge.sizeInBytes()-1,msg);
    case EMD:
        set_bit(data_car[0],0);
        return EMDSteg::emdImbedded(data_car+1,m_carrierIamge.sizeInBytes()-1,msg);
    default:
        break;
    }
    return false;
}

bool SteganographyOnImage::imbedded(QByteArray &&msg, Method method)
{
    auto data_car=m_carrierIamge.bits();
    switch (method) {
    case LSB:
        clr_bit(data_car[0],0);
        return LSBSteg::lsbImbedded(data_car+1,m_carrierIamge.sizeInBytes()-1,msg);
    case EMD:
        set_bit(data_car[0],0);
        return EMDSteg::emdImbedded(data_car+1,m_carrierIamge.sizeInBytes()-1,msg);
    default:
        break;
    }
    return false;
}

bool SteganographyOnImage::imbedded(QImage &image, const QByteArray &msg, Method method)
{
    auto data_car=image.bits();
    switch (method) {
    case LSB:
        clr_bit(data_car[0],0);
        return LSBSteg::lsbImbedded(data_car+1,image.sizeInBytes()-1,msg);
    case EMD:
        set_bit(data_car[0],0);
        return EMDSteg::emdImbedded(data_car+1,image.sizeInBytes()-1,msg);
    default:
        break;
    }
    return false;
}

QImage SteganographyOnImage::imbedded(QImage &&image, const QByteArray &msg, Method method)
{
    auto data_car=image.bits();
    switch (method) {
    case LSB:
        clr_bit(data_car[0],0);
        if(LSBSteg::lsbImbedded(data_car+1,image.sizeInBytes()-1,msg)){
            return image;
        }
        break;
    case EMD:
        set_bit(data_car[0],0);
        if(EMDSteg::emdImbedded(data_car+1,image.sizeInBytes()-1,msg)){
            return image;
        }
        break;
    default:
        break;
    }
    return QImage();
}

QImage SteganographyOnImage::imbedded(const QImage &cimage, const QByteArray &msg, Method method)
{
    QImage image=cimage;
    auto data_car=image.bits();
    switch (method) {
    case LSB:
        clr_bit(data_car[0],0);
        if(LSBSteg::lsbImbedded(data_car+1,image.sizeInBytes()-1,msg)){
            return image;
        }
        break;
    case EMD:
        set_bit(data_car[0],0);
        if(EMDSteg::emdImbedded(data_car+1,image.sizeInBytes()-1,msg)){
            return image;
        }
        break;
    default:
        break;
    }
    return QImage();
}

QByteArray SteganographyOnImage::retrieval()
{
    auto data_car=m_carrierIamge.bits();
    switch (get_bit(data_car[0],0)) {
    case 0:
        return LSBSteg::lsbRetrieval(data_car+1,m_carrierIamge.sizeInBytes());
    case 1:
        return EMDSteg::emdRetrieval(data_car+1,m_carrierIamge.sizeInBytes());
    default:
        break;
    }
    return QByteArray();
}

QByteArray SteganographyOnImage::retrieval(const QImage &image)
{
    auto data_car=image.bits();
    switch (get_bit(data_car[0],0)) {
    case 0:
        return LSBSteg::lsbRetrieval(data_car+1,image.sizeInBytes());
    case 1:
        return EMDSteg::emdRetrieval(data_car+1,image.sizeInBytes());
    default:
        break;
    }
    return QByteArray();
}

QByteArray SteganographyOnImage::retrieval(QImage &&image)
{
    auto data_car=image.bits();
    switch (get_bit(data_car[0],0)) {
    case 0:
        return LSBSteg::lsbRetrieval(data_car+1,image.sizeInBytes());
    case 1:
        return EMDSteg::emdRetrieval(data_car+1,image.sizeInBytes());
    default:
        break;
    }
    return QByteArray();
}
